package com.mfz.common.dbHelper

import com.alibaba.fastjson.JSONObject
import com.mfz.common.units.logger
import com.mfz.common.units.readFileContentByString
import org.apache.logging.log4j.LogManager
import java.sql.Connection
import java.sql.DriverManager

internal const val DB_SERVER_ADD = "DBServerAdd"
internal const val DB_SERVER_PORT = "DBServerPort"
internal const val DB_DATA_BASE_NAME = "DBDataBaseName"
internal const val DB_PASSWORD = "DBPassword"
internal const val DB_USER_NAME = "DBUserName"
internal const val CONNECTION_TIMEOUT = "ConnectionTimeout"
internal const val DB_POOL_NUM = "DBPoolNum"

/**
 * 数据库操作对象入口.
 *
 * create by 2017/6/1.
 * @author yimin
 */
object JDBCHelperFactory {
	private val log = LogManager.getLogger(JDBCHelperFactory::class.java.name)
	private val config: JSONObject
	internal val connectionPools: HashMap<String, ConnectionPool> = HashMap()
	val default: ConnectionPool

	init {
		log.trace("开始初始化数据库帮助管理对象.")
		config = JSONObject.parseObject(readFileContentByString("db.json"))
		config.forEach { t, u -> connectionPools[t] = createHelper(u as JSONObject) }

		default = connectionPools["default"]!!
	}

	private fun createHelper(config: JSONObject): ConnectionPool {
		return when (config["DBType"]) {
			"MSSQL" -> createMSSQLServerPools(config)
			"ORACLE" -> createOraclePools(config)
			"PGSQL" -> createPostgresqlPools(config)
			"MYSQL" -> createMySqlPools(config)
			"H2" -> createH2Pools(config)
			else -> throw IllegalArgumentException("类型都乱指定，你想闹哪样：${config["DBType"]}，去看db.json文件。")
		}
	}

	private fun createH2Pools(@Suppress("UNUSED_PARAMETER") config: JSONObject): ConnectionPool {
		TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
	}

	private fun createMySqlPools(@Suppress("UNUSED_PARAMETER") config: JSONObject): ConnectionPool {
		TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
	}

	private fun createOraclePools(@Suppress("UNUSED_PARAMETER") config: JSONObject): ConnectionPool {
		TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
	}

	private fun createMSSQLServerPools(@Suppress("UNUSED_PARAMETER") config: JSONObject): ConnectionPool {
		TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
	}

	private fun createPostgresqlPools(config: JSONObject): ConnectionPool {
		Class.forName("org.postgresql.Driver")
		val connectionUrl =
				"jdbc:postgresql://${config[DB_SERVER_ADD]}:${config[DB_SERVER_PORT]}/${config[DB_DATA_BASE_NAME]}"

		val createConnection = fun(): Connection {
			logPool.debug("创建一个新的连接。$connectionUrl")
			return DriverManager.getConnection(
					connectionUrl,
					config.getString(DB_USER_NAME),
					config.getString(DB_PASSWORD)
			)
		}

		val createHelper = fun(next: Helper?, pool: ConnectionPool): Helper {
			return PostgreSql(config["trim"] as String, next, createConnection(), pool, createConnection)
		}

		return ConnectionPool(config.getLong(CONNECTION_TIMEOUT), config.getInteger(DB_POOL_NUM), createHelper)
	}

	fun close() {
		for ((_, v) in connectionPools) {
			v.close()
		}
	}
}


/**
 * 返回与当前线程相关的连接对象。在同一个线程当中多次调用，得到的应该是同一个对象。
 */
val dbHelper get() = JDBCHelperFactory.default.getThreadHelper()

/**
 * 返回独立的连接对象。每调用一次此属性，必返回一个单独的连接对象。此对象在使用
 *
 * 需要手动释放。除查询和执行语句后会自动调用 close()。
 * 如使用了useAloneHelper.format() 方法时也会自动得到一个Helper的对象。
 */
val useAloneDBHelper get() = JDBCHelperFactory.default.getFreeHelper()

/**
 * 返回与当前线程相关的连接对象是否存在
 */
fun containsThreadDBHelper(): Boolean = JDBCHelperFactory.default.contains()

/**
 * 返回与当前线程相关的连接对象。在同一个线程当中多次调用，得到的应该是同一个对象。
 */
fun getDBHelper(name: String): Helper {
	return JDBCHelperFactory.connectionPools[name]!!.getThreadHelper()
}

/**
 * 返回独立的连接对象。每调用一次此属性，必返回一个单独的连接对象。此对象在使用
 *
 * 需要手动释放。除查询和执行语句后会自动调用 close()。
 * 如使用了useAloneDBHelper.format() 方法时也会自动得到一个Helper的对象。
 */
fun getUseAloneDBHelper(name: String): Helper = JDBCHelperFactory.connectionPools[name]!!.getFreeHelper()


/**
 * 返回与当前线程相关的连接对象是否存在
 */
fun containsAloneThreadDBHelper(name: String): Boolean = JDBCHelperFactory.connectionPools[name]!!.contains()

/**
 *
 * 此方法将开启一个事务，所有调用此方法的exec\query\format等方法将在同一个事务内执行。
 * 此事务与线程统一的事务是分开的。
 */
inline fun <T> tranExec(noinline errorHandle: ((Exception) -> T)? = null, crossinline block: Helper.() -> T): T {
	val helper = JDBCHelperFactory.default.getFreeHelper()
	return try {
		helper.beginTran()
		val result = helper.block()
		helper.commit()
		helper.close(true, closeThread = false)
		result
	} catch (e: Exception) {
		helper.rollback()
		if (errorHandle != null) {
			errorHandle(e)
		} else {
			logger.error("执行操作出现异常，回滚，异常：", e)
			throw e
		}
	}
}